﻿//-----------------------------------------------------------------------
// <copyright file="ExceptionExtensionsUnitTest.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics
{
    using System;

    using System.Collections.Generic;

    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;

    using System.Security;
    using System.Security.Principal;

    using System.Threading;
    using System.Threading.Tasks;

    using System.Xml.Linq;

    using CodePlex.Diagnostics.Services;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Provides unit tests for the <see cref="T:CodePlex.Diagnostics.ExceptionExtensions"/> class.
    /// </summary>
    [TestClass]
    public sealed class ExceptionExtensionsUnitTest
    {
        #region public ExceptionExtensionsUnitTest()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:ExceptionExtensionsUnitTest"/> class.
        /// </summary>
        public ExceptionExtensionsUnitTest()
        {
        }

        #endregion

        #region public TestContext TestContext

        /// <summary>
        /// Gets or sets the test context which provides information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext
        {
            get;
            set;
        }

        #endregion

        #region public void PublishException()

        /// <summary>
        /// Publish the exception and ensures that the appropriate publication Id is returned from the service.
        /// </summary>
        [TestMethod]
        public void PublishException()
        {
            try
            {
                try
                {
                    for (int index = 0; index < 10; index++)
                    {
                        index /= index;
                    }
                }
                catch (DivideByZeroException ex)
                {
                    // publish the DivideByZeroException as the inner exception of an InvalidOperationException.
                    Guid publicationId = new InvalidOperationException(ex.Message, ex).Publish();
                    
                    Assert.AreNotEqual<Guid>(publicationId, Guid.Empty, "The publication id should not be equal to Guid.Empty.");

                    throw new PublishedException(publicationId, ex);
                }
            }
            catch (PublishedException ex)
            {
                Assert.AreNotEqual<Guid>(ex.PublicationId, Guid.Empty, "PublishedException contains the incorrect publication Id.");

                Assert.AreEqual<Guid>(ex.Publish(), ex.PublicationId, "PublishedException contains the incorrect publication id.");
            }
        }

        #endregion

        #region public void PublishExceptionDictionary()

        /// <summary>
        /// Publish the exception and associated dictionary.
        /// </summary>
        [TestMethod]
        public void PublishExceptionDictionary()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }
            }
            catch (DivideByZeroException ex)
            {
                IIdentity identity = WindowsIdentity.GetCurrent() as IIdentity;

                Dictionary<string, string> dictionary = new Dictionary<string, string>();

                dictionary.Add("System.Type", "System.DivideByZeroException");

                XElement element = XElement.Parse("<?xml version=\"1.0\" encoding=\"utf-8\"?><xelement>unit test</xelement>");

                ex.Publish(dictionary, element, identity);
            }
        }

        #endregion

        #region public void PublishAggregateException()

        /// <summary>
        /// Publish the aggregate exception and ensures that the appropriate publication Id is returned from the service.
        /// </summary>
        [TestMethod]
        public void PublishAggregateException()
        {
            try
            {
                Parallel.Invoke(() => 
                                      { 
                                          for (int index = 0; index < 10; index++) 
                                          { 
                                              index /= index; 
                                          } 
                                      },
                                () =>
                                      {
                                          for (int index = 0; index < 10; index++)
                                          {
                                              index /= index;
                                          }
                                      });
            }
            catch (AggregateException ex)
            {
                Guid publicationId = ex.Publish();

                Assert.AreNotEqual<Guid>(publicationId, Guid.Empty, "PublishedException contains the incorrect publication Id.");
            }
        }

        #endregion

        #region public void PublishUnhandledException()

        /// <summary>
        /// Publish the exception and ensures that the appropriate publication Id is returned from the service.
        /// </summary>
        [TestMethod]
        public void PublishUnhandledException()
        {
            try
            {
                for (int index = 0; index < 10; index++)
                {
                    index /= index;
                }
            }
            catch (DivideByZeroException ex)
            {
                this.UnhandledException(this, new UnhandledExceptionEventArgs(ex, false));
            }            
        }

        #endregion

        #region private void UnhandledException(object sender, UnhandledExceptionEventArgs e)

        /// <summary>
        /// Publishes an unhandled exception.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.UnhandledExceptionEventArgs"/> instance containing the event data.</param>
        private void UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            DivideByZeroException ex = e.ExceptionObject as DivideByZeroException;

            ex.Publish();
        }

        #endregion
    }
}